home *** CD-ROM | disk | FTP | other *** search
/ Merciful 1 / Merciful - Disc 1.iso / software / f / friday_night_pool / fridaynightpool.dms / fridaynightpool.adf / source / comp.c next >
C/C++ Source or Header  |  1978-02-25  |  13KB  |  507 lines

  1. #include <exec/types.h>
  2.  
  3. #define CUE 0
  4. #define BLK 5
  5.  
  6. #define BASE 200 /* V.important constant. Used in ALL physical calcs. */
  7. #define BASESP 1000
  8. #define BASEII 4 /* For root calcs which need plenty of precision */
  9.  
  10. #define TABLELENGTH (272 * BASE) /* 272 is actual length in pixels */
  11. #define TABLEWIDTH ((TABLELENGTH * 5 / 8)-BASE)
  12.  
  13. #define X1CORNER 24
  14. #define Y1CORNER 62
  15. #define X2CORNER (X1CORNER + TABLELENGTH / BASE)
  16. #define Y2CORNER (Y1CORNER + TABLEWIDTH / BASE)
  17.  
  18. #define BALLRADIUS (7 * BASE) /* 7 pixels */
  19. #define BALLDIAMETER (BALLRADIUS * 2)
  20. #define SCRNBALLDIAMETER (BALLDIAMETER / BASE)
  21. #define SEMICIRCRAD (TABLEWIDTH/6)
  22. #define PLACEPACK (TABLELENGTH * 5 / 8)
  23. #define PACKHORIZSEP (BALLDIAMETER - 2*BASE)
  24. #define POCKET (BALLRADIUS + 5*BASE)
  25. #define NEARPOCKET (9*BASE)
  26. #define SCRNPOCKET (POCKET / BASE)
  27. #define CUETIP 10
  28. #define MAXCUELENGTH 80
  29.  
  30. #define CLOCKWISE 1
  31. #define ANTICLOCKWISE 2
  32. #define SMALL 1
  33. #define LARGE 2
  34. #define UP 1
  35. #define DOWN 2
  36. #define NOHIT -1
  37. #define ON TRUE
  38. #define OFF FALSE
  39. #define HIT 3
  40. #define UPDATE 3
  41. #define ICON 2
  42.  
  43. #define FRICTION (BASESP / 500)
  44. #define SPINFRICTION 3
  45. #define SPEEDINC (BASESP / 16)
  46. #define MAXSPEED (BASESP * 4)
  47.  
  48. #define DEFAULT 30000
  49.  
  50. #define RACKED 1
  51. #define BROKEN 0
  52. #define OPEN 2
  53.  
  54. #define PRACTICE 2
  55.  
  56. #define CLEARJAWS 0
  57. #define BALLINJAWS 1
  58. #define AVOIDJAWS 2
  59.  
  60. void ChangePower();
  61. void ChangeSpin(void);
  62. void DrawCross(short);
  63. void MoveCue(short,short);
  64. short FindAngle(WORD,WORD,WORD);
  65. short TouchingBall(short);
  66. void PlayComputerShot(void);
  67. void CopyBalls(struct ballstruct *,struct ballstruct *);
  68. WORD QuickRoot(long);
  69. void CheckAngle(short *);
  70. short NearPocket(short);
  71. short CheckPocket(short);
  72. UWORD Rand(UWORD);
  73.  
  74. enum msg { MSG_PLACECUEBALL,MSG_FOUL,MSG_WINS,MSG_MICHAEL,MSG_JOSH,
  75.     MSG_CLAIRE,MSG_SALLY,MSG_PLAYER1,MSG_PLAYER2,MSG_QUITTING,
  76.     MSG_VS,MSG_GAME,MSG_OF,MSG_0,MSG_1,MSG_2,MSG_3,MSG_4,MSG_5,
  77.     MSG_GOODSHOT,MSG_SHOTCANCELLED,MSG_BADLUCK,MSG_WELLDONE,
  78.     MSG_QUITGAME,MSG_ISTHECHAMP,MSG_OOOPS };
  79.  
  80. enum balltype { white,black,yellow,red, anyball,baize };
  81. struct ballstruct
  82. {
  83.     enum balltype colour;
  84.     char potted,justpotted,hasmoved,lasthit,olddx,olddy;
  85.     USHORT x,y;
  86.     short speed,angle,scrnx,scrny,oldscrnx,oldscrny;
  87. };
  88. struct ballstruct ball[16],tempball[16];
  89.  
  90. struct playerstruct
  91. {
  92.     enum balltype colour;
  93.     char goes,wins;
  94.     char nametag;
  95.     short maxpower;
  96.     char cuepulls,skill;
  97. };
  98. struct playerstruct player[8];
  99.  
  100. short *memblock, *quicksin, *quickcos, *quickarcsin;
  101.  
  102. WORD cueangle,cuespeed,powerdirn,spinx,spiny;
  103.  
  104. short gametype,cloth,firsthit,packstate,turn,foul,balls,
  105.     endofgame,cheatangle,cheatball;
  106.  
  107. USHORT pocketx[6] = { (TABLELENGTH-BALLRADIUS),(TABLELENGTH-BALLRADIUS),
  108.     (TABLELENGTH/2),(TABLELENGTH/2),BALLRADIUS,BALLRADIUS };
  109.  
  110. USHORT pockety[6] = { (TABLEWIDTH-BALLRADIUS),BALLRADIUS,
  111.     (TABLEWIDTH-BALLRADIUS),BALLRADIUS,(TABLEWIDTH-BALLRADIUS),BALLRADIUS };
  112.     
  113. char angleused[360];    
  114.  
  115. /**********************/
  116. short TouchingBall(col)
  117. short col;
  118. {
  119.     register short i;
  120.     
  121.     for (i=0; i<balls; i++)
  122.     {
  123.         if (!ball[i].potted && i!=col)
  124.         {
  125.             register long dx = ball[col].x - ball[i].x;
  126.             
  127.             if (dx < BALLDIAMETER && dx > (-BALLDIAMETER))
  128.             {
  129.                 register long dy = ball[col].y - ball[i].y;
  130.                 if (dy < BALLDIAMETER && dy > (-BALLDIAMETER))
  131.                     if (QuickRoot(dx*dx + dy*dy) < BALLDIAMETER)
  132.                         return(i);
  133.             }
  134.         }
  135.     }
  136.     return(NOHIT);
  137. }
  138. /************************/
  139. short NearPocket(i)
  140. short i;
  141. {
  142.     char j;
  143.     
  144.     for (j=0; j<6; j++)
  145.         if (abs(ball[i].x - pocketx[j]) < NEARPOCKET &&
  146.             abs(ball[i].y - pockety[j]) < NEARPOCKET) return(TRUE);
  147.     return(FALSE);
  148. }
  149. /************************/
  150. short CheckPocket(i)
  151. short i;
  152. {
  153.     short j;
  154.     
  155.     for (j=1; j<balls; j++)
  156.     {
  157.         if (!ball[j].potted &&
  158.             abs(ball[j].x - pocketx[i]) < NEARPOCKET &&
  159.             abs(ball[j].y - pockety[i]) < NEARPOCKET) return(j);
  160.     }
  161.     return(FALSE);
  162. }
  163. /************************/
  164. void PlayComputerShot()
  165. {
  166.     short i,j,k,l,limit,opp,adj,dx,dy,angle,hitball,
  167.         hypcue,anglecol,hypcol,anglecue,relangle,
  168.         potspeed=DEFAULT,hitspeed=DEFAULT,speed,
  169.         potangle,hitangle,potbackspin,nearpocket,
  170.         jaws,forgetcolour=FALSE;
  171.     
  172.     long x,y;
  173.     
  174.     CopyBalls(ball,tempball);
  175.     
  176.     /* CPU can forget its ball colour! */
  177.     if (player[turn].skill==0 && player[turn].colour!=black && !(Rand(10)))
  178.         forgetcolour=TRUE;
  179.     
  180.     for(i=1; i<balls; i++)
  181.     if ((ball[i].colour==player[turn].colour ||
  182.         (forgetcolour && ball[i].colour!=black) ||
  183.         (ball[i].colour!=black && player[turn].colour==anyball) ||
  184.         gametype==PRACTICE) && !ball[i].potted)
  185.     {
  186.         for (j=0; j < (6+1); j++)
  187.         {
  188.             if (j==6)
  189.             {
  190.                 opp = (ball[i].x - ball[CUE].x) / BASEII;
  191.                 adj = (ball[i].y - ball[CUE].y) / BASEII;
  192.                 hypcue = QuickRoot(opp*opp + adj*adj);
  193.                 anglecue = FindAngle(opp,adj,hypcue);
  194.                 anglecol = anglecue; hypcol = hypcue;
  195.                 relangle = 0;
  196.             }
  197.             else
  198.             {
  199.                 opp = (pocketx[j] - ball[i].x) / BASEII;
  200.                 adj = (pockety[j] - ball[i].y) / BASEII;
  201.                 hypcol = QuickRoot(opp*opp + adj*adj);
  202.                 anglecol = FindAngle(opp,adj,hypcol);
  203.  
  204.                 x = ball[i].x - SCRNBALLDIAMETER * quicksin[anglecol];
  205.                 y = ball[i].y - SCRNBALLDIAMETER * quickcos[anglecol];
  206.                 opp = (x - ball[CUE].x) / BASEII;
  207.                 adj = (y - ball[CUE].y) / BASEII;
  208.                 hypcue = QuickRoot(opp*opp + adj*adj);
  209.                 anglecue = FindAngle(opp,adj,hypcue);
  210.                 relangle = abs(anglecol-anglecue);
  211.                 if (relangle > 180) relangle=360-relangle;    
  212.             }
  213.             if (relangle < 70)
  214.             {
  215.                 dx = quicksin[anglecue]<<1;
  216.                 dy = quickcos[anglecue]<<1;
  217.                 limit = hypcue / ((BASE<<1)/BASEII) + 10;
  218.                 
  219.                 for (k=0; k<limit; k++)
  220.                 {
  221.                     hitball=TouchingBall(CUE);
  222.                     if (hitball!=NOHIT) break;
  223.                     ball[CUE].x+=dx; ball[CUE].y+=dy;
  224.                 }
  225.                 nearpocket = NearPocket(CUE);
  226.  
  227.                 ball[CUE].x = tempball[CUE].x;
  228.                 ball[CUE].y = tempball[CUE].y;
  229.     
  230.                 if (hitball!=NOHIT && hitball!=i && !nearpocket &&
  231.                     (ball[hitball].colour==player[turn].colour ||
  232.                     (player[turn].colour==anyball &&
  233.                     ball[hitball].colour!=black)))
  234.                 {
  235.                     speed = hypcue * (BASEII*MAXSPEED/BASE) / 600;
  236.                 
  237.                     if (speed < hitspeed)
  238.                     { hitspeed = speed; hitangle = anglecue; }
  239.                 }
  240.                 else if (hitball==i && !nearpocket)
  241.                 {
  242.                     /* Cue ball path is clear */
  243.                     
  244.                     dx = quicksin[anglecol] << 1;
  245.                     dy = quickcos[anglecol] << 1;
  246.  
  247.                     do
  248.                     {
  249.                         ball[i].x += dx; ball[i].y += dy;
  250.                         hitball = TouchingBall(i);
  251.                         if (ball[i].x < BALLRADIUS ||
  252.                             ball[i].x > (TABLELENGTH-BALLRADIUS) ||
  253.                             ball[i].y < BALLRADIUS ||
  254.                             ball[i].y > (TABLEWIDTH-BALLRADIUS)) break;
  255.                     
  256.                     } while (hitball==NOHIT);
  257.  
  258.                     ball[i].x = tempball[i].x;
  259.                     ball[i].y = tempball[i].y;
  260.                      
  261.                     if (hitball==NOHIT && j!=6) /* We've found a pot! */
  262.                     {
  263.                         speed = (hypcol+hypcue) * (BASEII*MAXSPEED/BASE)
  264.                             / ((100-relangle)*4)
  265.                             * (hypcol+(TABLELENGTH/BASEII))
  266.                             / (hypcue+(TABLELENGTH/BASEII));
  267.                     
  268.                         if (speed < potspeed)
  269.                         {
  270.                             potspeed = speed; potangle = anglecue;
  271.                             /* check for in/off situ */
  272.                             if (relangle < 5 || NearPocket(i))
  273.                                 potbackspin = TRUE;
  274.                             else potbackspin = FALSE;
  275.                             if (player[turn].nametag==MSG_JOSH ||
  276.                                 player[turn].nametag==MSG_PLAYER1 ||
  277.                                 player[turn].nametag==MSG_PLAYER2)
  278.                             { cheatangle = anglecol; cheatball = i; }
  279.                         }
  280.                     }
  281.                     else if (potspeed==DEFAULT)
  282.                     {
  283.                         /* Can hit but not pot */
  284.                     
  285.                         if (hitball!=NOHIT && NearPocket(hitball))
  286.                         {
  287.                             if (ball[hitball].colour==
  288.                                 player[turn].colour ||
  289.                                 (player[turn].colour==anyball &&
  290.                                 ball[hitball].colour!=black))
  291.                                 jaws = BALLINJAWS;
  292.                             else jaws = AVOIDJAWS;
  293.                         }
  294.                         else jaws = CLEARJAWS;
  295.                 
  296.                         speed = hypcue * (BASEII*MAXSPEED/BASE)
  297.                             / ((100-relangle)*3);
  298.                         if (jaws==BALLINJAWS) speed<<=2;
  299.                         
  300.                         if (speed < hitspeed && jaws!=AVOIDJAWS)
  301.                         {
  302.                             hitspeed = speed;
  303.                             hitangle = anglecue;
  304.                         }
  305.                     }
  306.                 }
  307.             }
  308.         }
  309.     }
  310.     
  311.     if (hitspeed==DEFAULT && potspeed==DEFAULT) /* Snooker situation */
  312.     {
  313.         for(i=1; i<balls; i++)
  314.         if ((ball[i].colour==player[turn].colour ||
  315.             (ball[i].colour!=black && player[turn].colour==anyball) ||
  316.             gametype==PRACTICE) && !ball[i].potted)
  317.         {
  318.             for (j=0; j<4; j++) for (l=0; l<5; l++)
  319.             {
  320.                 short xdisp,ydisp;
  321.                 long dx,dy;
  322.                                 
  323.                 switch(l)
  324.                 {
  325.                     case 0: xdisp = 0; ydisp = 0; break;
  326.                     
  327.                     case 1: xdisp = (-BALLRADIUS);
  328.                         ydisp = (-BALLRADIUS); break;
  329.                         
  330.                     case 2: xdisp = BALLRADIUS;
  331.                         ydisp = (-BALLRADIUS); break;
  332.                         
  333.                     case 3: xdisp = (-BALLRADIUS);
  334.                         ydisp = BALLRADIUS; break;
  335.                         
  336.                     case 4: xdisp = BALLRADIUS;
  337.                         ydisp = BALLRADIUS; break;
  338.                 }
  339.                 
  340.                 dx = ball[i].x+xdisp - ball[CUE].x;
  341.                 dy = ball[i].y+ydisp - ball[CUE].y;
  342.                 
  343.                 switch(j)
  344.                 {
  345.                     case 0:    y = ball[CUE].y +
  346.                             dy * ball[CUE].x /
  347.                             (ball[i].x+xdisp + ball[CUE].x);
  348.                             x = BALLRADIUS; break;
  349.  
  350.                     case 1:    y = ball[CUE].y +
  351.                             dy * (TABLELENGTH - ball[CUE].x) /
  352.                             ((TABLELENGTH - (ball[i].x+xdisp)) +
  353.                             (TABLELENGTH - ball[CUE].x));
  354.                             x = TABLELENGTH - BALLRADIUS; break;
  355.  
  356.                     case 2:    x = ball[CUE].x +
  357.                             dx * ball[CUE].y /
  358.                             (ball[i].y+ydisp + ball[CUE].y);
  359.                             y = BALLRADIUS; break;
  360.  
  361.                     case 3:    x = ball[CUE].x +
  362.                             dx * (TABLEWIDTH - ball[CUE].y) /
  363.                             ((TABLEWIDTH - (ball[i].y+ydisp)) +
  364.                             (TABLEWIDTH - ball[CUE].y));
  365.                             y = TABLEWIDTH - BALLRADIUS; break;
  366.                 }
  367.                 opp = (x - ball[CUE].x) / BASEII;
  368.                 adj = (y - ball[CUE].y) / BASEII;
  369.                 hypcue = QuickRoot(opp*opp + adj*adj);
  370.                 anglecue = FindAngle(opp,adj,hypcue);
  371.  
  372.                 opp = (x - (ball[i].x+xdisp)) / BASEII;
  373.                 adj = (y - (ball[i].y+ydisp)) / BASEII;
  374.                 hypcol = QuickRoot(opp*opp + adj*adj);
  375.  
  376.                 dx = quicksin[anglecue] << 1;
  377.                 dy = quickcos[anglecue] << 1;
  378.                 
  379.                 do
  380.                 {
  381.                     ball[CUE].x += dx; ball[CUE].y += dy;
  382.                     if (ball[CUE].x < BALLRADIUS ||
  383.                         ball[CUE].x > (TABLELENGTH-BALLRADIUS) ||
  384.                         ball[CUE].y < BALLRADIUS ||
  385.                         ball[CUE].y > (TABLEWIDTH-BALLRADIUS)) break;
  386.                     
  387.                     hitball = TouchingBall(CUE);
  388.                     
  389.                 } while (hitball==NOHIT);
  390.                 
  391.                 if (hitball==NOHIT && !(NearPocket(CUE)))
  392.                 {
  393.                     /* Path to cushion is clear */
  394.                     if (j <= 1) dx = -dx; else dy = -dy;
  395.     
  396.                     limit = (hypcol / ((BASE<<1)/BASEII)) + 10;
  397.                 
  398.                     for (k=0; k<limit; k++)
  399.                     {
  400.                         hitball=TouchingBall(CUE);
  401.                         if (hitball!=NOHIT) break;
  402.                         ball[CUE].x += dx; ball[CUE].y += dy;
  403.                     }
  404.             
  405.                     if (hitball==i)
  406.                     {
  407.                         /* Found a path off a cushion! */
  408.                         speed = (hypcue+hypcol) *
  409.                             (BASEII*MAXSPEED/BASE) / 300;
  410.                         if (speed < hitspeed)
  411.                         {
  412.                             hitspeed = speed;
  413.                             hitangle = anglecue;
  414.                             ball[CUE].x = tempball[CUE].x;
  415.                             ball[CUE].y = tempball[CUE].y;
  416.                             break;
  417.                         }
  418.                     }
  419.                 }
  420.                 ball[CUE].x = tempball[CUE].x;
  421.                 ball[CUE].y = tempball[CUE].y;
  422.             }
  423.         }
  424.     }
  425.  
  426.     spiny = (Rand(1200)+Rand(1200))/2 - 800;    
  427.  
  428.     if (potspeed != DEFAULT)
  429.     {
  430.         ball[CUE].speed = potspeed + Rand((UWORD)(potspeed>>1)); 
  431.         ball[CUE].angle = potangle;
  432.         if (potbackspin) /* could be an "in/off" situ */
  433.             spiny = (Rand(800)+Rand(800))/2 - 800;
  434.     }
  435.     else if (hitspeed != DEFAULT)
  436.     {
  437.         ball[CUE].speed = hitspeed + Rand(MAXSPEED);
  438.         ball[CUE].angle = hitangle;
  439.     }
  440.     else /* Ooops! We're fully snookered! */
  441.     {
  442.         short lasthope=FALSE;
  443.         
  444.         /* Try to illegally knock in any of our balls over pockets */
  445.         for (i=0; i<6; i++)
  446.         {
  447.             if ((j = CheckPocket(i)) &&
  448.                 ball[j].colour==player[turn].colour &&
  449.                 (player[turn].colour!=black ||
  450.                 (player[turn].colour==anyball &&
  451.                 ball[j].colour!=black)))
  452.             {
  453.                 opp = (pocketx[i] - ball[CUE].x) / BASEII;
  454.                 adj = (pockety[i] - ball[CUE].y) / BASEII;
  455.                 hypcue = QuickRoot(opp*opp + adj*adj);
  456.                 ball[CUE].angle = FindAngle(opp,adj,hypcue);
  457.                 ball[CUE].speed = player[turn].maxpower;
  458.                 spiny = (Rand(800)+Rand(800))/2 - 800;
  459.                 lasthope = TRUE; break;
  460.             }
  461.         }
  462.         if (!lasthope)
  463.         {
  464.             ball[CUE].angle = Rand(360);
  465.             ball[CUE].speed = player[turn].maxpower;
  466.             /* little anim! */
  467.             j = 36 + Rand(49);
  468.             for (i=0; i<j; i++) MoveCue(CLOCKWISE,LARGE);
  469.         }
  470.     }
  471.     if (packstate==RACKED) ball[CUE].speed = player[turn].maxpower;
  472.     
  473.     /* Add player characteristics */
  474.     angle = ((Rand(8)-4) * (3-player[turn].skill))/3;
  475.     if (player[turn].colour==black) angle*=2;
  476.     ball[CUE].angle+=angle;
  477.     CheckAngle(&ball[CUE].angle);
  478.  
  479.     ball[CUE].speed = ball[CUE].speed * player[turn].maxpower / MAXSPEED;
  480.     if (ball[CUE].speed > player[turn].maxpower)
  481.         ball[CUE].speed = player[turn].maxpower;
  482.     if (ball[CUE].speed < BASESP) ball[CUE].speed=BASESP;
  483.     if (ball[CUE].speed > MAXSPEED) ball[CUE].speed=MAXSPEED;
  484.     
  485.     angle = ball[CUE].angle+180;
  486.     CheckAngle(&angle);
  487.     
  488.     i=LARGE; j=0;
  489.     while(cueangle!=angle)
  490.     {
  491.         if ((angle-cueangle<180 && angle-cueangle>=0) ||
  492.             angle-cueangle<-180)
  493.         {
  494.             if (j==2) i=SMALL;
  495.             j=1; MoveCue(CLOCKWISE,i);
  496.         }
  497.         else
  498.         {
  499.             if (j==1) i=SMALL;
  500.             j=2; MoveCue(ANTICLOCKWISE,i);
  501.         }
  502.     }
  503.  
  504.     while(cuespeed < ball[CUE].speed) { ChangePower(); WaitTOF(); }
  505.     PlayShot();
  506. }
  507.